/*
 * DBHelper.cpp
 *
 *  Created on: Jan 23, 2012
 *      Author: hduser
 */

#include <stdlib.h>
#include <iostream>
#include <stdarg.h>
#include "DBHelper.h"
#include "prepared_statement.h"


using namespace std;
using namespace sql;

namespace database {

const char* HOST = "localhost";
const char* USER = "root";
const char* PASS = "root";
const char* DB = "dCDN";

DBHelper::DBHelper() {

	try {
		sql::Driver * driver = sql::mysql::get_driver_instance();
		con = driver->connect(HOST, USER, PASS);
		con->setSchema(DB);
	} catch (sql::SQLException &e) {
		/*
		The MySQL Connector/C++ throws three different exceptions:

		- sql::MethodNotImplementedException (derived from sql::SQLException)
		- sql::InvalidArgumentException (derived from sql::SQLException)
		- sql::SQLException (derived from std::runtime_error)
		*/
		cerr << "# ERR: SQLException in " << __FILE__;
		cerr << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		/* Use what() (derived from std::runtime_error) to fetch the error message */
		cerr << "# ERR: " << e.what();
		cerr << " (MySQL error code: " << e.getErrorCode();
		cerr << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
}

DBHelper::~DBHelper() {

	cout<<"delete DBHelper"<<endl;
	try {
		if (con != NULL) {
			con->close();
			delete con;
		}
	} catch (sql::SQLException &e) {
		/*
		The MySQL Connector/C++ throws three different exceptions:

		- sql::MethodNotImplementedException (derived from sql::SQLException)
		- sql::InvalidArgumentException (derived from sql::SQLException)
		- sql::SQLException (derived from std::runtime_error)
		*/
		cerr << "# ERR: SQLException in " << __FILE__;
		cerr << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		/* Use what() (derived from std::runtime_error) to fetch the error message */
		cerr << "# ERR: " << e.what();
		cerr << " (MySQL error code: " << e.getErrorCode();
		cerr << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
}

void DBHelper::disconnectDB() {
	cout<<"delete DBHelper"<<endl;
	try {
		if (con != NULL) {
			con->close();
			delete con;
		}
	} catch (sql::SQLException &e) {
		/*
		The MySQL Connector/C++ throws three different exceptions:

		- sql::MethodNotImplementedException (derived from sql::SQLException)
		- sql::InvalidArgumentException (derived from sql::SQLException)
		- sql::SQLException (derived from std::runtime_error)
		*/
		cerr << "# ERR: SQLException in " << __FILE__;
		cerr << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		/* Use what() (derived from std::runtime_error) to fetch the error message */
		cerr << "# ERR: " << e.what();
		cerr << " (MySQL error code: " << e.getErrorCode();
		cerr << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
}

int DBHelper::logErrorToDB_1(char* host, char* clientip, char* serverip, char* location, char* errormsg, char* note) {

	try {

		//Statement* stmt = con->createStatement();
		//stmt->execute("");


		cout<< "in logErrorToDB - " << errormsg << endl;

		sql::PreparedStatement* pstmt = con->prepareStatement("CALL spiErrorLog(?,?,?,?,?,?)");

		if (host != NULL)
			pstmt->setString(1, host);
		else
			pstmt->setString(1, "null");

		if (clientip != NULL)
			pstmt->setString(2, clientip);
		else
			pstmt->setString(2, "null");

		if (serverip != NULL)
			pstmt->setString(3, serverip);
		else
			pstmt->setString(3, "null");

		if (location != NULL)
			pstmt->setString(4, location);
		else
			pstmt->setString(4, "null");

		if (errormsg!= NULL)
			pstmt->setString(5, errormsg);
		else
			pstmt->setString(5, "null");

		if (note != NULL)
			pstmt->setString(6, note);
		else
			pstmt->setString(6, "null");

		pstmt->execute();

		delete pstmt;


		return EXIT_SUCCESS;

	} catch (sql::SQLException &e) {
		/*
		The MySQL Connector/C++ throws three different exceptions:

		- sql::MethodNotImplementedException (derived from sql::SQLException)
		- sql::InvalidArgumentException (derived from sql::SQLException)
		- sql::SQLException (derived from std::runtime_error)
		*/
		cerr << "# ERR: SQLException in " << __FILE__;
		cerr << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		/* Use what() (derived from std::runtime_error) to fetch the error message */
		cerr << "# ERR: " << e.what();
		cerr << " (MySQL error code: " << e.getErrorCode();
		cerr << ", SQLState: " << e.getSQLState() << " )" << endl;

		return EXIT_FAILURE;
	}
}

int DBHelper::logErrorToDB(char* host, char* clientip, char* serverip, char* location, char* errormsg, char* note) {
	return ExecuteNonQuery("CALL spiErrorLog(?,?,?,?,?,?)", "ssssss", host, clientip, serverip, location, errormsg, note);
}

sql::ResultSet* DBHelper::checkRequest(int VendorID, char* file) {
	return ExecuteQuery("CALL spsActiveRequest(?,?)", "is", VendorID, file);
}

sql::ResultSet* DBHelper::getEdgeServerGroup() {
	return ExecuteQuery("CALL spsEdgeServerGroup()", "");
}

sql::ResultSet* DBHelper::getEdgeServersInGroup(int EdgeServerGroupID) {
	return ExecuteQuery("CALL spsEdgeServersInGroup(?)", "i",EdgeServerGroupID);
}

sql::ResultSet* DBHelper::createRequest(int VendorID, char* file, char* dateUpdated, size_t fileSize, int chunkCount, int EdgeServerGroupID) {
	return ExecuteQuery("CALL spiRequest(?,?,?,?,?,?)", "issbii", VendorID, file, dateUpdated, fileSize, chunkCount, EdgeServerGroupID);
}

sql::ResultSet* DBHelper::createRequestItem(int RequestID, int chunkIndex, size_t chunkSize, int EdgeServerID) {
	return ExecuteQuery("CALL spiRequestItem(?,?,?,?)", "iibi", RequestID, chunkIndex, chunkSize, EdgeServerID);
}

int DBHelper::updateRequestStatus(int RequestID, int RequestStatusID) {
	return ExecuteNonQuery("CALL spuRequestStatus(?,?)", "ii", RequestID, RequestStatusID);
}

int DBHelper::makeRequestInactive(int RequestID) {
	return ExecuteNonQuery("CALL spuMakeRequestInActive(?)", "i", RequestID);
}

int DBHelper::updateRequestItemStatus(int RequestItemID, int RequestItemStatusID) {
	return ExecuteNonQuery("CALL spuRequestItemStatus(?,?)", "ii", RequestItemID, RequestItemStatusID);
}

sql::ResultSet* DBHelper::getActiveRequestItems(int VendorID, char* file) {
	return ExecuteQuery("CALL spsRequestItemsForRequest(?,?)", "is", VendorID, file);
}


int DBHelper::ExecuteNonQuery(char* command, char* argtypes, ...) {

	try {

		va_list vl;
		int i;

		va_start(vl, argtypes);

		//Statement* stmt = con->createStatement();
		//stmt->execute("");

		cout<< "in ExecuteNonQuery - " << endl;

		sql::PreparedStatement* pstmt = con->prepareStatement(command);

		// Step through the list.
		for( i = 0; argtypes[i] != '\0'; i++ ) {

		  switch( argtypes[i] ) {   // Type to expect.
			  // integer
			 case 'i':
				pstmt->setInt(i+1, va_arg( vl, int ));
			 break;

			 // double
			 case 'f':
				 pstmt->setDouble(i+1, va_arg( vl, double ));
			 break;

			 // big integer
			 case 'b':
				 pstmt->setInt64(i+1, va_arg( vl, size_t ));
			 break;

			 // char*
			 case 's':
				 pstmt->setString(i+1, va_arg( vl, char* ));
			 break;

			 default:
			 break;
		  }
	   }

	   pstmt->execute();

	   delete pstmt;
	   va_end( vl );

	   return EXIT_SUCCESS;

	} catch (sql::SQLException &e) {
		/*
		The MySQL Connector/C++ throws three different exceptions:

		- sql::MethodNotImplementedException (derived from sql::SQLException)
		- sql::InvalidArgumentException (derived from sql::SQLException)
		- sql::SQLException (derived from std::runtime_error)
		*/
		cerr << "# ERR: SQLException in " << __FILE__;
		cerr << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		/* Use what() (derived from std::runtime_error) to fetch the error message */
		cerr << "# ERR: " << e.what();
		cerr << " (MySQL error code: " << e.getErrorCode();
		cerr << ", SQLState: " << e.getSQLState() << " )" << endl;

		return EXIT_FAILURE;
	}
}

sql::ResultSet* DBHelper::ExecuteQuery(char* command, char* argtypes, ...) {

	try {

		va_list vl;
		int i;

		va_start(vl, argtypes);

		//Statement* stmt = con->createStatement();
		//stmt->execute("");

		cout<< "in ExecuteNonQuery - " << endl;

		sql::PreparedStatement* pstmt = con->prepareStatement(command);

		sql::ResultSet *res;

		// Step through the list.
		for( i = 0; argtypes[i] != '\0'; i++ ) {

		  switch( argtypes[i] ) {   // Type to expect.
			 case 'i':
				pstmt->setInt(i+1, va_arg( vl, int ));
			 break;

			 case 'f':
				 pstmt->setDouble(i+1, va_arg( vl, double ));
			 break;

			 case 'b':
				 pstmt->setInt64(i+1, va_arg( vl, size_t ));
			 break;

			 case 's':
				 pstmt->setString(i+1, va_arg( vl, char* ));
			 break;

			 default:
			 break;
		  }
	   }

	   res = pstmt->executeQuery();

	   delete pstmt;
	   va_end( vl );

	   return res;

	} catch (sql::SQLException &e) {
		/*
		The MySQL Connector/C++ throws three different exceptions:

		- sql::MethodNotImplementedException (derived from sql::SQLException)
		- sql::InvalidArgumentException (derived from sql::SQLException)
		- sql::SQLException (derived from std::runtime_error)
		*/
		cerr << "# ERR: SQLException in " << __FILE__;
		cerr << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		/* Use what() (derived from std::runtime_error) to fetch the error message */
		cerr << "# ERR: " << e.what();
		cerr << " (MySQL error code: " << e.getErrorCode();
		cerr << ", SQLState: " << e.getSQLState() << " )" << endl;

		return NULL;
	}
}

}
